﻿// Inner Fire 游戏引擎库
// MESH的创建器
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 用于生成简单的模型。根据《DirectX12游戏开发实战》中的工具类修改。
// 原作者：Frank Luna
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-19

#include "geometry_generator.h"

namespace ifire {
// 一些快捷方式
constexpr float PI = DirectX::XM_PI;

GeometryGenerator::MeshData ifire::GeometryGenerator::CreateCylinder(
    float bottom_radius, float top_radius, float height, uint32 slice_count,
    uint32 stack_count) {
  MeshData mesh;

  /*
   * 构建堆叠层
   */

  // 每层的高度
  float stack_height = height / stack_count;
  // 计算从下至上，遍历每个相邻分层时所需要的半径增量
  float radius_step = (top_radius - bottom_radius) / stack_count;

  // 上下的半径比例，用于计算副切线。如果上下一样。副切线会变成(0,-height,0)这样。
  float dradius = bottom_radius - top_radius;

  // 一共需要多少个环（因为每层一个加封顶，所以比stack_count多一个）
  uint32 ring_count = stack_count + 1;

  // 模型的原点（-0.5f * height）意味着这个圆柱体的原点在几何中心位置。
  // 如果在底座，应该值为（0）。
  float origin = -0.5f * height;

  // 从底面开始，由下至上计算每个堆叠层环上的顶点坐标
  for (uint32 i = 0; i < ring_count; ++i) {
    // 得到当前层的Y轴位置。
    float y = origin + i * stack_height;
    // 得到当前层的半径
    float r = bottom_radius + i * radius_step;

    // 得到每个扇区的弧度
    float theta = 2.0f * PI / slice_count;

    // 当前层的帖图V，放在这里可以省一些计算
    float tex_v = 1.0f - static_cast<float>(i) / stack_count;

    // 环上的各个顶点
    for (uint32 j = 0; j <= slice_count; ++j) {
      Vertex vertex;

      // 通过三角函数确定点的位置
      float cos_theta = cosf(j * theta);
      float sin_theta = sinf(j * theta);
      // 按照国际惯例，弧度的0点是从正X轴开始，然后逆时针转动。
      // 我就是没搞这个规则，把切线算错了。
      vertex.Position.x = r * cos_theta;
      vertex.Position.y = y;
      vertex.Position.z = r * sin_theta;

      // 设置贴图
      // j为环上的index，与slice_count相除得到一个百分比值。
      vertex.TexC.x = static_cast<float>(j) / slice_count;
      vertex.TexC.y = tex_v;

      // 切线。为单位长度。
      // 切线的指向方向是和UV对应的。
      // 切换使用的是余角法则，所以这里x和z与坐标正好正反。
      // sin(θ+90)=cos(θ)
      // cos⁡(θ+90)=−sin⁡(θ)cos(θ+90∘)=−sin(θ)
      vertex.TangentU = XMFLOAT3(-sin_theta, 0.0f, cos_theta);
      // 得到副切线
      XMFLOAT3 bitangent(dradius * cos_theta, -height, dradius * sin_theta);

      // 通过切线和副切线的叉乘来计算法线
      XMVECTOR T = XMLoadFloat3(&vertex.TangentU);
      XMVECTOR B = XMLoadFloat3(&bitangent);
      XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B));
      XMStoreFloat3(&vertex.Normal, N);

      // 加入队列
      mesh.Vertices.push_back(vertex);
    }
  }

  // +1
  // 是希望让每环的第一个顶点和最后一个顶点重合，这是因为它们的纹理坐标并不相同
  uint32 ring_vertex_count = slice_count + 1;

  // 计算每个侧面块中三角形的索引
  for (uint32 i = 0; i < stack_count; ++i) {
    for (uint32 j = 0; j < slice_count; ++j) {
      mesh.Indices32.push_back(i * ring_vertex_count + j);
      mesh.Indices32.push_back((i + 1) * ring_vertex_count + j);
      mesh.Indices32.push_back((i + 1) * ring_vertex_count + j + 1);

      mesh.Indices32.push_back(i * ring_vertex_count + j);
      mesh.Indices32.push_back((i + 1) * ring_vertex_count + j + 1);
      mesh.Indices32.push_back(i * ring_vertex_count + j + 1);
    }
  }

  BuildCylinderTopCap(
      bottom_radius, top_radius, height, slice_count, stack_count, mesh);
  BuildCylinderBottomCap(
      bottom_radius, top_radius, height, slice_count, stack_count, mesh);

  return mesh;
}

void GeometryGenerator::BuildCylinderTopCap(float bottom_radius,
    float top_radius, float height, uint32 slice_count, uint32 stack_count,
    MeshData& mesh) {
  // 因为索引已经构架，所以需要继承索引的位置
  uint32 base_index = (uint32)mesh.Vertices.size();

  // 原点位置
  XMFLOAT3 pos = {0, 0.5f * height, 0};
  // 每扇形的弧度
  float theta = 2.0f * PI / slice_count;

  // 切线和法线是永远不会变化的
  XMFLOAT3 normal(0.0f, 1.0f, 0.0f);
  XMFLOAT3 tangent(1.0f, 0.0f, 0.0f);

  // 使用圆台面环上的首尾顶点重合，因为这两个顶点的纹理坐标和法线是不同的
  for (uint32 i = 0; i <= slice_count; ++i) {
    // 使用三角函数计算位置
    pos.x = top_radius * cosf(i * theta);
    pos.z = top_radius * sinf(i * theta);

    // 根据圆台的高度，使顶面纹理坐标的范围按比例缩小
    XMFLOAT2 uv(pos.x / height + 0.5f, pos.z / height + 0.5f);

    mesh.Vertices.push_back(Vertex(pos, normal, tangent, uv));
  }

  // 顶面的中心顶点
  mesh.Vertices.push_back(Vertex(XMFLOAT3(0, 0.5f * height, 0), //
      normal, tangent, XMFLOAT2(0.5f, 0.5f)));
  // 中心顶点的索引值
  uint32 center_index = (uint32)mesh.Vertices.size() - 1;

  // 遍历项目（从中心点一个扇面一个扇面配置）
  for (uint32 i = 0; i < slice_count; ++i) {
    mesh.Indices32.push_back(center_index);
    mesh.Indices32.push_back(base_index + i + 1);
    mesh.Indices32.push_back(base_index + i);
  }
}

void GeometryGenerator::BuildCylinderBottomCap(float bottom_radius,
    float top_radius, float height, uint32 slice_count, uint32 stack_count,
    MeshData& mesh) {
  // 因为索引已经构架，所以需要继承索引的位置
  uint32 base_index = (uint32)mesh.Vertices.size();

  // 原点位置
  XMFLOAT3 pos = {0, -0.5f * height, 0};
  // 每扇形的弧度
  float theta = 2.0f * PI / slice_count;

  // 切线和法线是永远不会变化的
  XMFLOAT3 normal(0.0f, -1.0f, 0.0f);
  XMFLOAT3 tangent(1.0f, 0.0f, 0.0f);

  // 使用圆台面环上的首尾顶点重合，因为这两个顶点的纹理坐标和法线是不同的
  for (uint32 i = 0; i <= slice_count; i++) {
    // 使用三角函数计算位置
    pos.x = bottom_radius * cosf(i * theta);
    pos.z = bottom_radius * sinf(i * theta);

    // 根据圆台的高度，使顶面纹理坐标的范围按比例缩小
    XMFLOAT2 uv(pos.x / height + 0.5f, pos.z / height + 0.5f);

    mesh.Vertices.push_back(Vertex(pos, normal, tangent, uv));
  }

  // 顶面的中心顶点
  mesh.Vertices.push_back(Vertex(XMFLOAT3(0, -0.5f * height, 0), //
      normal, tangent, XMFLOAT2(0.5f, 0.5f)));
  // 中心顶点的索引值
  uint32 center_index = (uint32)mesh.Vertices.size() - 1;

  // 遍历项目（从中心点一个扇面一个扇面配置）
  for (uint32 i = 0; i < slice_count; i++) {
    mesh.Indices32.push_back(center_index);
    mesh.Indices32.push_back(base_index + i + 1);
    mesh.Indices32.push_back(base_index + i);
  }
}

GeometryGenerator::MeshData GeometryGenerator::CreateSphere(
    float radius, uint32 slice_count, uint32 stack_count) {
  MeshData mesh;

  // 设置最顶部和最底部的顶点
  // 切线是不会变换的
  XMFLOAT3 tangent(1.0f, 0.0f, 0.0f);
  // 顶部
  XMFLOAT3 position_top(0.0f, radius, 0.0f);
  XMFLOAT3 normal_top(0.0f, 1.0f, 0.0f); // 向上
  XMFLOAT2 uv_top(0.0f, 0.0f);
  Vertex vertex_top(position_top, normal_top, tangent, uv_top);
  // 底部
  XMFLOAT3 position_bottom(0.0f, -radius, 0.0f);
  XMFLOAT3 normal_bottom(0.0f, -1.0f, 0.0f); // 向下
  XMFLOAT2 uv_bottom(0.0f, 1.0f);
  Vertex vertex_bottom(position_bottom, normal_bottom, tangent, uv_bottom);

  // 将顶部加入
  mesh.Vertices.push_back(vertex_top);

  // 用于计算圆环（经度）每个扇面（只有半圆）
  float phi_step = XM_PI / stack_count;
  // 用于计算圆环（纬度）每个扇面
  float theta_step = 2.0f * XM_PI / slice_count;

  // 依次进行每个环的配置（开始点为1，结束点为count-1，即去头尾）
  for (uint32 i = 1; i <= stack_count - 1; ++i) {
    float phi = i * phi_step;
    float sin_phi = sinf(phi);

    // 计算圆环（纬度）
    for (uint32 j = 0; j <= stack_count; ++j) {
      float theta = j * theta_step;
      float cos_theta = cosf(theta);
      float sin_theta = sinf(theta);

      Vertex v;

      // 球坐标到直角坐标系转换
      v.Position.x = radius * sin_phi * cos_theta;
      v.Position.y = radius * cosf(phi);
      v.Position.z = radius * sin_phi * sin_theta;

      // P 对 theta 的偏导数
      v.TangentU.x = -radius * sin_phi * sin_theta;
      v.TangentU.y = 0.0f;
      v.TangentU.z = +radius * sin_phi * cos_theta;

      XMVECTOR T = XMLoadFloat3(&v.TangentU);
      XMStoreFloat3(&v.TangentU, XMVector3Normalize(T));

      XMVECTOR P = XMLoadFloat3(&v.Position);
      XMStoreFloat3(&v.Normal, XMVector3Normalize(P));

      v.TexC.x = theta / XM_2PI;
      v.TexC.y = phi / XM_PI;

      mesh.Vertices.push_back(v);
    }
  }
  // 最后一个是尾部
  mesh.Vertices.push_back(vertex_bottom);

  // 计算顶部的索引。顶部是最先写入顶点缓冲区的，并且连接顶部极点到第一个环。
  for (uint32 i = 1; i <= slice_count; ++i) {
    mesh.Indices32.push_back(0);
    mesh.Indices32.push_back(i + 1);
    mesh.Indices32.push_back(i);
  }

  // 计算内部栈的索引（不与极点相连）。
  // 将索引偏移至第一个环的第一个顶点的索引。这仅仅是跳过顶部极点的顶点。
  uint32 base_index = 1;
  uint32 ring_vertex_count = slice_count + 1;
  for (uint32 i = 0; i < stack_count - 2; ++i) {
    for (uint32 j = 0; j < slice_count; ++j) {
      mesh.Indices32.push_back(base_index + i * ring_vertex_count + j);
      mesh.Indices32.push_back(base_index + i * ring_vertex_count + j + 1);
      mesh.Indices32.push_back(base_index + (i + 1) * ring_vertex_count + j);

      mesh.Indices32.push_back(base_index + (i + 1) * ring_vertex_count + j);
      mesh.Indices32.push_back(base_index + i * ring_vertex_count + j + 1);
      mesh.Indices32.push_back(
          base_index + (i + 1) * ring_vertex_count + j + 1);
    }
  }

  // 计算底部的索引。底部是最后写入顶点缓冲区的，并且连接底部极点到底部环。
  uint32 south_pole_index = (uint32)mesh.Vertices.size() - 1;
  // 将索引偏移至最后一个环的第一个顶点的索引。
  base_index = south_pole_index - ring_vertex_count;
  for (uint32 i = 0; i < slice_count; ++i) {
    mesh.Indices32.push_back(south_pole_index);
    mesh.Indices32.push_back(base_index + i);
    mesh.Indices32.push_back(base_index + i + 1);
  }

  return mesh;
}

GeometryGenerator::MeshData GeometryGenerator::CreateGeoshpere(
    float radius, uint32 sub_divisions) {
  MeshData mesh;

  // 确定细分的次数
  sub_divisions = std::min<uint32>(sub_divisions, 6u);

  // 通过对正20面体进行曲面细分来逼近一个球体
  const float X = 0.525731f;
  const float Z = 0.850651f;

  XMFLOAT3 pos[12] = {
      XMFLOAT3(-X, 0.0f, Z), XMFLOAT3(X, 0.0f, Z),   //
      XMFLOAT3(-X, 0.0f, -Z), XMFLOAT3(X, 0.0f, -Z), ///
      XMFLOAT3(0.0f, Z, X), XMFLOAT3(0.0f, Z, -X),   //
      XMFLOAT3(0.0f, -Z, X), XMFLOAT3(0.0f, -Z, -X), //
      XMFLOAT3(Z, X, 0.0f), XMFLOAT3(-Z, X, 0.0f),   //
      XMFLOAT3(Z, -X, 0.0f), XMFLOAT3(-Z, -X, 0.0f)  //
  };

  uint32 k[60] = {
      1, 4, 0, 4, 9, 0, 4, 5, 9, 8, 5, 4, 1, 8, 4,     //
      1, 10, 8, 10, 3, 8, 8, 3, 5, 3, 2, 5, 3, 7, 2,   //
      3, 10, 7, 10, 6, 7, 6, 11, 7, 6, 0, 11, 6, 1, 0, //
      10, 1, 6, 11, 0, 9, 2, 11, 9, 5, 2, 9, 11, 2, 7  //
  };

  mesh.Vertices.resize(12);
  mesh.Indices32.assign(&k[0], &k[60]);

  for (uint32 i = 0; i < 12; ++i) {
    mesh.Vertices[i].Position = pos[i];
  }

  for (uint32 i = 0; i < sub_divisions; ++i) {
    Subdivide(mesh);
  }

  // 将顶点投影到球面，并且推导其对应的纹理坐标
  for (uint32 i = 0; i < mesh.Vertices.size(); ++i) {
    // 印射到单位球面
    XMVECTOR n = XMVector3Normalize(XMLoadFloat3(&mesh.Vertices[i].Position));
    // 印射到球面
    XMVECTOR p = radius * n;

    XMStoreFloat3(&mesh.Vertices[i].Position, p);
    XMStoreFloat3(&mesh.Vertices[i].Normal, n);

    // 根据球面坐标推导出纹理坐标
    float theta =
        atan2f(mesh.Vertices[i].Position.z, mesh.Vertices[i].Position.x);

    // 将theta限制在[0, 2pi]区间
    if (theta < 0.0f) {
      theta += XM_2PI;
    }

    float phi = acosf(mesh.Vertices[i].Position.y / radius);

    mesh.Vertices[i].TexC.x = theta / XM_2PI;
    mesh.Vertices[i].TexC.y = phi / XM_PI;

    // 求出P关于theta(p对于theta)的偏导数
    mesh.Vertices[i].TangentU.x = -radius * sinf(phi) * sinf(theta);
    mesh.Vertices[i].TangentU.y = 0.0f;
    mesh.Vertices[i].TangentU.z = +radius * sinf(phi) * cosf(theta);

    XMVECTOR T = XMLoadFloat3(&mesh.Vertices[i].TangentU);
    XMStoreFloat3(&mesh.Vertices[i].TangentU, XMVector3Normalize(T));
  }

  return mesh;
}

void GeometryGenerator::Subdivide(MeshData& mesh) {
  // 得到一个输入项目的副本，并将原项目清空以组装
  MeshData input_copy = mesh;
  mesh.Vertices.resize(0);
  mesh.Indices32.resize(0);

  // 细分的思路非常简单，每一个新的顶点，就是原来原始三角形边上的中点。
  //       v1
  //       *
  //      / \
	//     /   \
	//  m0*-----*m1
  //   / \   / \
	//  /   \ /   \
	// *-----*-----*
  // v0    m2     v2

  // 得到三角型的数量（索引/3）
  uint32 num_triangles = (uint32)input_copy.Indices32.size() / 3;
  // 遍历每个三角形，得到顶点
  for (uint32 i = 0; i < num_triangles; ++i) {
    Vertex v0 = input_copy.Vertices[input_copy.Indices32[i * 3 + 0]];
    Vertex v1 = input_copy.Vertices[input_copy.Indices32[i * 3 + 1]];
    Vertex v2 = input_copy.Vertices[input_copy.Indices32[i * 3 + 2]];

    // 得到中间点
    Vertex m0 = MidPoint(v0, v1);
    Vertex m1 = MidPoint(v1, v2);
    Vertex m2 = MidPoint(v0, v2);

    // 通过中间点，生成4个小三角型
    mesh.Vertices.push_back(v0); // 0
    mesh.Vertices.push_back(v1); // 1
    mesh.Vertices.push_back(v2); // 2
    mesh.Vertices.push_back(m0); // 3
    mesh.Vertices.push_back(m1); // 4
    mesh.Vertices.push_back(m2); // 5

    mesh.Indices32.push_back(i * 6 + 0);
    mesh.Indices32.push_back(i * 6 + 3);
    mesh.Indices32.push_back(i * 6 + 5);

    mesh.Indices32.push_back(i * 6 + 3);
    mesh.Indices32.push_back(i * 6 + 4);
    mesh.Indices32.push_back(i * 6 + 5);

    mesh.Indices32.push_back(i * 6 + 5);
    mesh.Indices32.push_back(i * 6 + 4);
    mesh.Indices32.push_back(i * 6 + 2);

    mesh.Indices32.push_back(i * 6 + 3);
    mesh.Indices32.push_back(i * 6 + 1);
    mesh.Indices32.push_back(i * 6 + 4);
  }
}

GeometryGenerator::Vertex GeometryGenerator::MidPoint(
    const Vertex& v0, const Vertex& v1) {
  // 顶点，法线，切线，UV，都需要插值计算
  XMVECTOR p0 = XMLoadFloat3(&v0.Position);
  XMVECTOR p1 = XMLoadFloat3(&v1.Position);
  XMVECTOR n0 = XMLoadFloat3(&v0.Normal);
  XMVECTOR n1 = XMLoadFloat3(&v1.Normal);
  XMVECTOR tan0 = XMLoadFloat3(&v0.TangentU);
  XMVECTOR tan1 = XMLoadFloat3(&v1.TangentU);
  XMVECTOR tex0 = XMLoadFloat2(&v0.TexC);
  XMVECTOR tex1 = XMLoadFloat2(&v1.TexC);

  // 计算所有属性的中点。
  // 由于线性插值可能会使向量长度不再是单位长度，因此需要对向量进行归一化。
  XMVECTOR pos = 0.5f * (p0 + p1);
  XMVECTOR normal = XMVector3Normalize(0.5f * (n0 + n1));
  XMVECTOR tangent = XMVector3Normalize(0.5f * (tan0 + tan1));
  XMVECTOR tex = 0.5f * (tex0 + tex1);

  // 装载到顶点结构中
  Vertex v;
  XMStoreFloat3(&v.Position, pos);
  XMStoreFloat3(&v.Normal, normal);
  XMStoreFloat3(&v.TangentU, tangent);
  XMStoreFloat2(&v.TexC, tex);

  return v;
}

GeometryGenerator::MeshData GeometryGenerator::CreateBox(
    float width, float height, float depth, uint32 numSubdivisions) {
  MeshData mesh;

  // 生成顶点，固定由24个顶点组成。
  Vertex v[24];
  // 长宽高的半径
  float w2 = 0.5f * width;
  float h2 = 0.5f * height;
  float d2 = 0.5f * depth;

  // FRONT
  v[0] = Vertex(-w2, -h2, -d2, //
      0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  v[1] = Vertex(-w2, +h2, -d2, //
      0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  v[2] = Vertex(+w2, +h2, -d2, //
      0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  v[3] = Vertex(+w2, -h2, -d2, //
      0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

  // BACK
  v[4] = Vertex(-w2, -h2, +d2, //
      0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  v[5] = Vertex(+w2, -h2, +d2, //
      0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  v[6] = Vertex(+w2, +h2, +d2, //
      0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  v[7] = Vertex(-w2, +h2, +d2, //
      0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

  // TOP
  v[8] = Vertex(-w2, +h2, -d2, //
      0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  v[9] = Vertex(-w2, +h2, +d2, //
      0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  v[10] = Vertex(+w2, +h2, +d2, //
      0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  v[11] = Vertex(+w2, +h2, -d2, //
      0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

  // BOTTOM
  v[12] = Vertex(-w2, -h2, -d2, //
      0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  v[13] = Vertex(+w2, -h2, -d2, //
      0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  v[14] = Vertex(+w2, -h2, +d2, //
      0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  v[15] = Vertex(-w2, -h2, +d2, //
      0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

  // LEFT
  v[16] = Vertex(-w2, -h2, +d2, //
      -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
  v[17] = Vertex(-w2, +h2, +d2, //
      -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
  v[18] = Vertex(-w2, +h2, -d2, //
      -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
  v[19] = Vertex(-w2, -h2, -d2, //
      -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);

  // RIGHT
  v[20] = Vertex(+w2, -h2, -d2, //
      1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
  v[21] = Vertex(+w2, +h2, -d2, //
      1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
  v[22] = Vertex(+w2, +h2, +d2, //
      1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
  v[23] = Vertex(+w2, -h2, +d2, //
      1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);

  mesh.Vertices.assign(&v[0], &v[24]);

  // 创建索引，固定为36个索引
  uint32 i[36];

  // FRONT
  i[0] = 0;
  i[1] = 1;
  i[2] = 2;
  i[3] = 0;
  i[4] = 2;
  i[5] = 3;

  // BACK
  i[6] = 4;
  i[7] = 5;
  i[8] = 6;
  i[9] = 4;
  i[10] = 6;
  i[11] = 7;

  // TOP
  i[12] = 8;
  i[13] = 9;
  i[14] = 10;
  i[15] = 8;
  i[16] = 10;
  i[17] = 11;

  // BOTTOM
  i[18] = 12;
  i[19] = 13;
  i[20] = 14;
  i[21] = 12;
  i[22] = 14;
  i[23] = 15;

  // LEFT
  i[24] = 16;
  i[25] = 17;
  i[26] = 18;
  i[27] = 16;
  i[28] = 18;
  i[29] = 19;

  // RIGHT
  i[30] = 20;
  i[31] = 21;
  i[32] = 22;
  i[33] = 20;
  i[34] = 22;
  i[35] = 23;

  mesh.Indices32.assign(&i[0], &i[36]);

  // 对细分的数量设置上限。
  numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
  for (uint32 i = 0; i < numSubdivisions; ++i) {
    Subdivide(mesh);
  }
  

  return mesh;
}

GeometryGenerator::MeshData GeometryGenerator::CreateGrid(
    float width, float depth, uint32 m, uint32 n) {
  MeshData mesh;
  // 计算顶点数量
  uint32 vertex_count = m * n;
  // 顶点数量已经确定，可以通过[]设置，使用resize提升效率。
  mesh.Vertices.resize(vertex_count);

  // 计算面数量（为什么要-1，简单的数学关系）
  uint32 face_count = (m - 1) * (n - 1) * 2;

  // 生成顶点
  float half_width = 0.5f * width;
  float half_depth = 0.5f * depth;

  float dx = width / (n - 1);
  float dz = depth / (m - 1);

  float du = 1.0f / (n - 1);
  float dv = 1.0f / (m - 1);

  for (uint32 i = 0; i < m; ++i) {
    float z = half_depth - i * dz;
    for (uint32 j = 0; j < n; ++j) {
      float x = -half_width + j * dx;

      mesh.Vertices[i * n + j].Position = XMFLOAT3(x, 0.0f, z);
      mesh.Vertices[i * n + j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
      mesh.Vertices[i * n + j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);

      // 将纹理拉伸覆盖在网格上。
      mesh.Vertices[i * n + j].TexC.x = j * du;
      mesh.Vertices[i * n + j].TexC.y = i * dv;
    }
  }

  // 生成索引
  mesh.Indices32.resize(face_count * 3);

  // 遍历每个四边形并计算索引。
  uint32 k = 0;
  for (uint32 i = 0; i < m - 1; ++i) {
    for (uint32 j = 0; j < n - 1; ++j) {
      mesh.Indices32[k] = i * n + j;
      mesh.Indices32[k + 1] = i * n + j + 1;
      mesh.Indices32[k + 2] = (i + 1) * n + j;

      mesh.Indices32[k + 3] = (i + 1) * n + j;
      mesh.Indices32[k + 4] = i * n + j + 1;
      mesh.Indices32[k + 5] = (i + 1) * n + j + 1;

      k += 6; // Quad步进2个面（6索引）
    }
  }

  return mesh;
}

GeometryGenerator::MeshData GeometryGenerator::CreateQuad(
    float x, float y, float width, float height, float depth) {
  MeshData mesh;

  mesh.Vertices.resize(4);
  mesh.Indices32.resize(6);

  // 在NDC空间中指定的位置坐标。
  mesh.Vertices[0] = Vertex( //
      x, y - height, depth,  //
      0.0f, 0.0f, -1.0f,     //
      1.0f, 0.0f, 0.0f,      //
      0.0f, 1.0f);           //

  mesh.Vertices[1] = Vertex( //
      x, y, depth,           //
      0.0f, 0.0f, -1.0f,     //
      1.0f, 0.0f, 0.0f,      //
      0.0f, 0.0f);           //

  mesh.Vertices[2] = Vertex( //
      x + width, y, depth,   //
      0.0f, 0.0f, -1.0f,     //
      1.0f, 0.0f, 0.0f,      //
      1.0f, 0.0f);           //

  mesh.Vertices[3] = Vertex(        //
      x + width, y - height, depth, //
      0.0f, 0.0f, -1.0f,            //
      1.0f, 0.0f, 0.0f,             //
      1.0f, 1.0f);                  //

  mesh.Indices32[0] = 0;
  mesh.Indices32[1] = 1;
  mesh.Indices32[2] = 2;

  mesh.Indices32[3] = 0;
  mesh.Indices32[4] = 2;
  mesh.Indices32[5] = 3;

  return mesh;
}

void GeometryGenerator::ComputeAvgNormal(
    std::vector<Vertex>& vertices, const std::vector<uint32>& indices) {
  size_t triangles_count = indices.size() / 3;

  // 计算每个三角的法线，然后叠加给每个顶点
  for (size_t i = 0; i < triangles_count; i++) {
    auto& v0 = vertices[i * 3 + 0];
    auto& v1 = vertices[i * 3 + 1];
    auto& v2 = vertices[i * 3 + 2];

    auto p0 = XMLoadFloat3(&v0.Position);
    auto p1 = XMLoadFloat3(&v1.Position);
    auto p2 = XMLoadFloat3(&v2.Position);

    auto u = p1 - p0;
    auto v = p2 - p0;
    auto normal = XMVector3Cross(u, v);

    auto n0 = XMLoadFloat3(&v0.Normal);
    auto n1 = XMLoadFloat3(&v1.Normal);
    auto n2 = XMLoadFloat3(&v2.Normal);

    n0 += normal;
    n1 += normal;
    n2 += normal;

    XMStoreFloat3(&v0.Normal, n0);
    XMStoreFloat3(&v1.Normal, n1);
    XMStoreFloat3(&v2.Normal, n2);
  }

  // 因为已经进行了求和操作，所以只需要进行Normalize就行了。
  for (size_t i = 0; i < vertices.size(); i++) {
    auto normal = XMLoadFloat3(&vertices[i].Normal);
    auto normalized = XMVector3Normalize(normal);
    XMStoreFloat3(&vertices[i].Normal, normalized);
  }
}

void GeometryGenerator::MeshData::ComputeNormal() {
  GeometryGenerator::ComputeAvgNormal(Vertices, Indices32);
}

} // namespace ifire